package com.nuanshui.heatedloan.middleware.async.proxy;

import java.lang.reflect.Method;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import com.nuanshui.heatedloan.middleware.async.AsyncTemplate;
import com.nuanshui.heatedloan.middleware.async.bean.AsyncMethod;
import com.nuanshui.heatedloan.middleware.async.cache.AsyncProxyCache;
import com.nuanshui.heatedloan.middleware.async.core.AsyncExecutor;
import com.nuanshui.heatedloan.middleware.async.exception.AsyncException;
import com.nuanshui.heatedloan.middleware.async.pool.AsyncFutureTask;
import com.nuanshui.heatedloan.middleware.async.pool.AsyncPoolCallable;
import com.nuanshui.heatedloan.middleware.async.pool.AsyncRunnable;
import com.nuanshui.heatedloan.middleware.async.util.CommonUtil;
import com.nuanshui.heatedloan.middleware.async.util.ReflectionHelper;


/**
 * 异步执行方法的 interceptor
 * @param 
 * @author guohao
 * @date 2016年12月5日 下午4:35:13
 * @since $
 */
public class AsyncMethodInterceptor implements MethodInterceptor {

	private final static Logger logger = LoggerFactory.getLogger(AsyncMethodInterceptor.class);

	private long timeout;

	private Object targetObject;//目标对象

	private boolean all;

	public AsyncMethodInterceptor(Object targetObject, long timeout, boolean all) {
		this.timeout = timeout;
		this.targetObject = targetObject;
		this.all = all;
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		if (AsyncExecutor.isDestroyed()) {//如果 异步执行的线程池 destroyed 就直接和执行此方法
			return ReflectionHelper.invoke(targetObject, args, method);
		}
		String key = CommonUtil.buildkey(targetObject, method);//获取方法的key
		if (!all && !AsyncProxyCache.containMethod(key)) { //如果不存在直接执行
			return ReflectionHelper.invoke(targetObject, args, method);
		}

		final Object finObj = targetObject;
		final Object[] finArgs = args;
		final Method finMethod = method;

		long timeout = this.timeout;

		Class<?> returnClass = method.getReturnType();
		if (Void.TYPE.isAssignableFrom(returnClass)) {//如果返回void 则直接异步执行
			AsyncTemplate.execute(new AsyncRunnable() {
				@Override
				public void doAsync(Map<String, Object> dataMap) {
					try {
						ReflectionHelper.invoke(finObj, finArgs, finMethod);
					} catch (Throwable e) {
						logger.error("async runnable invoke error", e);
					}
				}
			});
			return null;
		}

		final AsyncMethod asyncMethod = AsyncProxyCache.getAsyncMethod(key);
		if (asyncMethod != null) {
			timeout = asyncMethod.getTimeout();
		}
		AsyncFutureTask<Object> future = AsyncExecutor.submit(new AsyncPoolCallable<Object>() {
					@Override
					public Object call() throws Exception {
						Object object = null;
						try {
							if (asyncMethod != null) {
								object = ReflectionHelper.invoke(asyncMethod.getObject(), finArgs,asyncMethod.getMethod());
							} else {
								object = ReflectionHelper.invoke(finObj,finArgs, finMethod);
							}
							return object;
						} catch (Throwable e) {
							throw new AsyncException("future invoke error", e);
						}
					}
		});		
		return new AsyncResultProxy(future).buildProxy(returnClass, timeout,true);
	}
}
